// File: jmcomic-core/src/main/java/dev/jukomu/jmcomic/entity/DetailEntity.java
package dev.jukomu.jmcomic.entity;

import dev.jukomu.jmcomic.config.JmModuleConfig;
import dev.jukomu.jmcomic.util.JmcomicText;
import lombok.EqualsAndHashCode;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

/**
 * 对应Python的DetailEntity，禁漫详情实体（本子或章节）的基类。
 * 提供了ID、标题、作者等通用属性。
 *
 * @param <T> 内部包含的子实体类型（例如JmPhotoDetail的T是JmImageDetail）
 */
@EqualsAndHashCode(callSuper = true)
public abstract class DetailEntity<T> extends JmBaseEntity implements IndexedEntity<T> {

    // 缓存属性Map，用于getPropertiesMap()，避免重复反射计算
    private transient Map<String, Object> propertiesCache = new ConcurrentHashMap<>();

    /**
     * 获取实体的ID。
     *
     * @return ID字符串
     */
    public abstract String getId();

    /**
     * 获取实体的标题。
     *
     * @return 标题字符串
     */
    public abstract String getTitle(); // 在Java中直接映射为getTitle()

    /**
     * 获取实体的作者。
     *
     * @return 作者字符串
     */
    public abstract String getAuthor();

    /**
     * 获取原始名称（original name）。
     * 例如：标题："喂我吃吧 老師! [欶瀾漢化組] [BLVEFO9] たべさせて、せんせい! (ブルーアーカイブ) [中國翻譯] [無修正]"
     * oname："喂我吃吧 老師!"
     *
     * @return 实体的原始名称
     */
    public String getOname() {
        String oname = JmcomicText.parseOrigAlbumName(getTitle());
        if (oname != null) {
            return oname;
        }
        JmModuleConfig.jmLog("entity", "无法提取出原名称: " + getTitle());
        return getTitle();
    }

    /**
     * 获取作者名与原始名称的组合。
     * 格式："【作者】原始名称"
     *
     * @return 作者名+原始名称组合
     */
    public String getAuthorOname() {
        return "【" + getAuthor() + "】" + getOname();
    }

    /**
     * 获取ID与原始名称的组合。
     * 格式："[ID] 原始名称"
     *
     * @return ID+原始名称组合
     */
    public String getIdOname() {
        return "[" + getId() + "] " + getOname();
    }

    @Override
    public String toString() {
        return String.format("%s(%s-%s: \"%s\")",
                getClass().getSimpleName(),
                getAlias(),
                getId(),
                getTitle());
    }

    /**
     * 获取实体的别名（例如"album", "photo"）。
     *
     * @return 别名字符串
     */
    public String getAlias() {
        String className = getClass().getSimpleName();
        int mIndex = className.indexOf('m'); // Find 'm' in JmAlbumDetail
        int detailIndex = className.lastIndexOf("Detail");
        if (mIndex != -1 && detailIndex != -1) {
            return className.substring(mIndex + 1, detailIndex).toLowerCase();
        }
        return className.toLowerCase(); // Fallback
    }

    /**
     * 获取用于目录名的值。
     * 该方法被DirRule调用，用于生成特定层次的文件夹名。
     *
     * @param detail 详情实体实例（本子或章节）
     * @param ref    字段名
     * @return 对应的目录名
     */
    public static String getDirname(DetailEntity<?> detail, String ref) {
        // 优先从 JmModuleConfig.AFIELD_ADVICE / PFIELD_ADVICE 中获取自定义函数并调用
        Function<?, String> adviceFunc;
        if (detail.isAlbum()) {
            adviceFunc = JmModuleConfig.AFIELD_ADVICE.get(ref);
        } else if (detail.isPhoto()) {
            adviceFunc = JmModuleConfig.PFIELD_ADVICE.get(ref);
        } else {
            adviceFunc = null;
        }

        if (adviceFunc != null) {
            // Unchecked cast: assuming adviceFunc's input type matches detail's type
            return ((Function<Object, String>) adviceFunc).apply(detail);
        }

        // 否则，通过反射获取属性值
        try {
            // 尝试直接通过getter方法获取属性
            String getterMethodName = "get" + ref.substring(0, 1).toUpperCase() + ref.substring(1);
            java.lang.reflect.Method getter = detail.getClass().getMethod(getterMethodName);
            Object value = getter.invoke(detail);
            return Objects.toString(value);
        } catch (NoSuchMethodException e) {
            // 如果没有getter方法，尝试直接访问字段
            try {
                java.lang.reflect.Field field = detail.getClass().getDeclaredField(ref);
                field.setAccessible(true); // 允许访问私有字段
                Object value = field.get(detail);
                return Objects.toString(value);
            } catch (NoSuchFieldException | IllegalAccessException fe) {
                // 如果字段也不存在，或者无法访问，则抛出异常
                throw new IllegalArgumentException("Unsupported field reference for dirname: " + ref + " in " + detail.getClass().getSimpleName(), fe);
            }
        } catch (Exception e) {
            // 其他反射异常
            throw new RuntimeException("Error accessing field for dirname: " + ref + " in " + detail.getClass().getSimpleName(), e);
        }
    }

    /**
     * 获取所有属性（包括字段、getter和Advice函数）的Map。
     * 用于DirRule的f-string规则解析。
     *
     * @return 包含所有属性的Map
     */
    public Map<String, Object> getPropertiesMap() {
        if (!propertiesCache.isEmpty()) {
            return propertiesCache;
        }

        // 每次调用时重新计算以确保最新状态，或者在属性变更时清除缓存
        // 这里的缓存机制是简单的，未考虑属性变更的通知
        Map<String, Object> result = new ConcurrentHashMap<>();
        String prefix = getAlias().substring(0, 1).toUpperCase(); // 'A' or 'P'

        // 1. 字段
        for (java.lang.reflect.Field field : getClass().getDeclaredFields()) {
            try {
                if (field.getName().equals("propertiesCache")) {
                    continue;
                }
                field.setAccessible(true);
                // 忽略transient字段，如propertiesCache
                if (!java.lang.reflect.Modifier.isTransient(field.getModifiers())) {
                    result.put(prefix + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1), field.get(this));
                }
            } catch (IllegalAccessException e) {
                // Ignore inaccessible fields
            } catch (NullPointerException e) {
                if (!java.lang.reflect.Modifier.isTransient(field.getModifiers())) {
                    result.put(prefix + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1), "");
                }
            }
        }

        // 2. Property (getter方法)
        for (java.lang.reflect.Method method : getClass().getMethods()) {
            if (method.getName().startsWith("get") && method.getParameterCount() == 0 && method.getReturnType() != void.class) {
                String propName = method.getName().substring(3);
                if (propName.equals("PropertiesMap")) {
                    continue;
                }
                if (propName.isEmpty()) continue;
                // Convert getter name (e.g., GetTitle -> Title)
                String formattedPropName = propName.substring(0, 1).toLowerCase() + propName.substring(1);
                try {
                    result.put(prefix + formattedPropName.substring(0, 1).toUpperCase() + formattedPropName.substring(1), method.invoke(this));
                } catch (Exception e) {
                    // Log error if getter invocation fails
                    result.put(prefix + formattedPropName.substring(0, 1).toUpperCase() + formattedPropName.substring(1), "ERROR");
                }
            }
        }
        // Fix for Author, Title, Id - Python uses original names without 'get' prefix
        result.put(prefix + "Author", getAuthor());
        result.put(prefix + "Title", getTitle());
        result.put(prefix + "Id", getId());
        result.put(prefix + "Oname", getOname());
        result.put(prefix + "AuthorOname", getAuthorOname());
        result.put(prefix + "IdOname", getIdOname());


        // 3. Advice (自定义函数)
        // 使用更通用的Function类型，并确保运行时类型安全
        // 由于AFIELD_ADVICE和PFIELD_ADVICE的Function参数是JmAlbumDetail或JmPhotoDetail，
        // 而当前实例(this)是DetailEntity，需要运行时判断this的实际类型并进行安全的类型转换。
        if (isAlbum()) {
            JmModuleConfig.AFIELD_ADVICE.forEach((name, func) -> {
                try {
                    // 假设JmModuleConfig.AFIELD_ADVICE中的函数接受JmAlbumDetail
                    String key = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
                    result.put(key, func.apply((JmAlbumDetail) this));
                } catch (Exception e) {
                    JmModuleConfig.jmLog("entity.advice.error", "Error applying album advice function " + name + ": " + e.getMessage());
                    result.put(prefix + name.substring(0, 1).toUpperCase() + name.substring(1), "ERROR");
                }
            });
        } else if (isPhoto()) {
            JmModuleConfig.PFIELD_ADVICE.forEach((name, func) -> {
                try {
                    // 假设JmModuleConfig.PFIELD_ADVICE中的函数接受JmPhotoDetail
                    String key = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
                    result.put(key, func.apply((JmPhotoDetail) this));
                } catch (Exception e) {
                    JmModuleConfig.jmLog("entity.advice.error", "Error applying photo advice function " + name + ": " + e.getMessage());
                    result.put(prefix + name.substring(0, 1).toUpperCase() + name.substring(1), "ERROR");
                }
            });
        }

        propertiesCache.putAll(result); // 缓存结果
        return result;
    }
}